import requests
import logging
import json
import time
from typing import Dict, Optional, List, Any, Union, Callable
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from app.conf.config import config, logger

# 确保使用配置中的日志系统，不再创建新的日志配置

class ShopifyApiService:
    """
    Shopify API服务
    用于与Shopify API交互，获取店铺信息、产品数据和操作metafield
    """
    
    # 从配置中获取API版本，默认使用最新稳定版
    DEFAULT_API_VERSION = getattr(config, "SHOPIFY_API_VERSION", "2024-04")
    
    # 重试配置
    DEFAULT_RETRY_CONFIG = {
        "total": getattr(config, "RETRY_ATTEMPTS", 3),
        "backoff_factor": getattr(config, "RETRY_BACKOFF_FACTOR", 0.5),
        "status_forcelist": [429, 500, 502, 503, 504],
        "allowed_methods": ["GET", "POST", "PUT", "DELETE"]
    }
    
    def __init__(self, api_key: str = "", api_secret: str = "", api_version: str = None, 
                 shop_domain: Optional[str] = None, access_token: Optional[str] = None):
        """
        初始化Shopify API服务
        
        Args:
            api_key: Shopify应用API密钥
            api_secret: Shopify应用API密钥
            api_version: Shopify API版本，默认为配置中的版本
            shop_domain: 店铺域名（可选，用于实例化特定店铺的API服务）
            access_token: 访问令牌（可选，用于实例化特定店铺的API服务）
        """
        # 从配置获取API凭证
        self.api_key = api_key or getattr(config, "SHOPIFY_API_KEY", "")
        self.api_secret = api_secret or getattr(config, "SHOPIFY_API_SECRET", "")
        self.api_version = api_version or self.DEFAULT_API_VERSION
        self.timeout = getattr(config, "API_TIMEOUT", 30)
        
        # 特定店铺的凭证
        self.shop_domain = shop_domain
        self.access_token = access_token
        
        # 配置代理（如果需要）
        self.proxies = None
        http_proxy = getattr(config, "HTTP_PROXY", None)
        https_proxy = getattr(config, "HTTPS_PROXY", None)
        if http_proxy and https_proxy:
            self.proxies = {
                'http': http_proxy,
                'https': https_proxy
            }
        
        # 初始化session并配置重试机制
        self.session = self._create_session()
        
        # 日志记录初始化信息
        logger.info(f"Shopify API服务初始化完成，API版本: {self.api_version}")
        if self.shop_domain:
            logger.info(f"服务已配置为特定店铺: {self.shop_domain}")

    
    def _create_session(self) -> requests.Session:
        """
        创建配置了重试机制的requests session
        
        Returns:
            requests.Session: 配置好的session对象
        """
        session = requests.Session()
        retry_config = self.DEFAULT_RETRY_CONFIG.copy()
        
        retry = Retry(
            total=retry_config["total"],
            backoff_factor=retry_config["backoff_factor"],
            status_forcelist=retry_config["status_forcelist"],
            allowed_methods=retry_config["allowed_methods"]
        )
        
        adapter = HTTPAdapter(max_retries=retry, pool_connections=20, pool_maxsize=50)
        session.mount("http://", adapter)
        session.mount("https://", adapter)
        
        return session
    
    def _make_request(self, method: str, url: str, headers: Dict[str, str], **kwargs) -> Optional[requests.Response]:
        """
        通用的HTTP请求方法，包含重试机制和错误处理
        
        Args:
            method: HTTP方法（GET, POST, PUT, DELETE等）
            url: 请求URL
            headers: 请求头
            **kwargs: 其他请求参数
            
        Returns:
            Optional[requests.Response]: HTTP响应，如果请求失败返回None
        """
        try:
            # 验证method
            if method not in ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD']:
                logger.error(f"无效的HTTP方法: {method}")
                return None
            
            # 验证URL是否包含有效域名
            if 'invalid-shop' in url or 'fallback' in url:
                logger.error(f"尝试使用无效URL: {url}")
                return None
            
            # 安全检查：确保URL是Shopify域名
            if 'myshopify.com' not in url:
                logger.error(f"安全警告: 尝试访问非Shopify域名: {url}")
                raise ValueError("不允许访问非Shopify域名的API请求")
            
            # 确保超时设置
            if 'timeout' not in kwargs:
                kwargs['timeout'] = self.timeout
            
            # 安全检查URL
            if not url.startswith('https://'):
                logger.error(f"非HTTPS URL: {url}")
                return None
            
            # 如果有请求体数据，记录脱敏的日志
            if 'json' in kwargs:
                # 不记录完整的请求体，仅记录请求类型
                logger.debug(f"发送API请求: {method} {url} (JSON数据)")
            elif 'data' in kwargs:
                logger.debug(f"发送API请求: {method} {url} (表单数据)")
            else:
                logger.debug(f"发送API请求: {method} {url}")
            
            # 添加Shopify API版本头
            if headers and isinstance(headers, dict):
                headers['X-Shopify-API-Version'] = self.api_version
            else:
                headers = {'X-Shopify-API-Version': self.api_version}
            
            # 使用session发送请求
            session = self.session
            logger.info(f"发送请求: {method} {url}")
            
            response = session.request(
                method=method,
                url=url,
                headers=headers,
                proxies=self.proxies,
                **kwargs
            )
            
            # 记录限流信息
            if 'X-Shopify-Shop-Api-Call-Limit' in response.headers:
                call_limit = response.headers['X-Shopify-Shop-Api-Call-Limit']
                logger.debug(f"API调用限制: {call_limit}")
            
            # 检查是否需要延迟以避免触发速率限制
            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 1))
                logger.warning(f"API速率限制触发，延迟 {retry_after} 秒后重试")
                time.sleep(retry_after)
                # 递归重试一次
                return self._make_request(method, url, headers, **kwargs)
                
            # 检查是否需要重试（服务器错误）
            elif response.status_code >= 500:
                logger.warning(f"服务器错误: {response.status_code}, 响应: {response.text}")
                
                # 重试机制 - 最多重试3次
                retry_count = kwargs.pop('retry_count', 0)
                if retry_count < 3:
                    retry_count += 1
                    backoff_time = 0.5 * (2 ** (retry_count - 1))  # 指数退避
                    logger.info(f"第 {retry_count} 次重试请求，等待 {backoff_time:.2f} 秒")
                    time.sleep(backoff_time)
                    return self._make_request(method, url, headers, retry_count=retry_count, **kwargs)
            
            logger.info(f"请求完成: {method} {url}, 状态码: {response.status_code}")
            return response
            
        except requests.Timeout:
            logger.error(f"请求超时: {method} {url}")
            return None
        except requests.ConnectionError:
            logger.error(f"连接错误: {method} {url}")
            return None
        except requests.RequestException as e:
            logger.error(f"HTTP请求异常: {str(e)}, URL: {url}")
            return None
        except Exception as e:
            logger.error(f"未知异常: {method} {url}, 错误: {str(e)}, 异常类型: {type(e).__name__}")
            return None
    
    def _build_shopify_url(self, shop_domain: str, endpoint: str) -> str:
        """
        构建Shopify API的完整URL
        
        Args:
            shop_domain: Shopify店铺域名
            endpoint: API端点
            
        Returns:
            str: 完整的Shopify API URL
        """
        try:
            # 确保shop_domain是有效的字符串
            if not isinstance(shop_domain, str) or not shop_domain:
                logger.error("构建Shopify URL失败: 无效的shop_domain")
                return "https://invalid-shop.myshopify.com/admin/api/default/invalid.json"
            
            # 确保域名格式正确（移除协议和尾部斜杠）
            if shop_domain.startswith(('http://', 'https://')):
                shop_domain = shop_domain.split('://', 1)[1]
            if shop_domain.endswith('/'):
                shop_domain = shop_domain[:-1]
            
            # 如果域名不包含myshopify.com，自动添加
            if not shop_domain.endswith('.myshopify.com'):
                shop_domain = f"{shop_domain}.myshopify.com"
            
            # 确保endpoint以/开头
            if endpoint and not endpoint.startswith('/'):
                endpoint = f"/{endpoint}"
            
            # 确保api_version有效
            api_version = self.api_version or "2024-04"
            
            # 修复URL构建逻辑，避免重复问题
            if '/admin/api/' in endpoint:
                # 如果endpoint已经包含完整路径，直接使用
                if not endpoint.endswith('.json'):
                    endpoint = f"{endpoint}.json"
                url = f"https://{shop_domain}{endpoint}"
            else:
                # 构建标准API URL
                url = f"https://{shop_domain}/admin/api/{api_version}{endpoint}.json"
            
            logger.debug(f"构建Shopify API URL: {url}")
            return url
        except Exception as e:
            logger.error(f"构建Shopify URL异常: {str(e)}")
            return "https://fallback.myshopify.com/admin/api/default/fallback.json"
    
    def _get_headers(self, access_token: str) -> Dict[str, str]:
        """
        获取Shopify API请求所需的标准头信息
        
        Args:
            access_token: Shopify访问令牌
            
        Returns:
            Dict: 请求头信息
        """
        try:
            # 验证access_token
            if not access_token:
                logger.warning("获取请求头警告: 空的access_token")
            
            return {
                'Content-Type': 'application/json',
                'X-Shopify-Access-Token': access_token or '',
                'Accept': 'application/json',
                'X-Shopify-API-Version': self.api_version
            }
        except Exception as e:
            logger.error(f"获取请求头异常: {str(e)}")
            return {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            }
    
    def get_shop_info(self, shop_domain: str, access_token: str) -> Optional[Dict]:
        """
        获取Shopify店铺基本信息
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            
        Returns:
            Dict: 店铺信息，如果获取失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, '/shop')
            headers = self._get_headers(access_token)
            
            logger.info(f"获取店铺信息: {shop_domain}")
            
            response = self._make_request('GET', url, headers)
            
            if response and response.status_code == 200:
                try:
                    data = response.json()
                    shop_data = data.get('shop', {})
                    
                    # 提取有用的店铺信息
                    shop_info = {
                        'shop_name': shop_data.get('name'),
                        'shop_owner': shop_data.get('shop_owner'),
                        'email': shop_data.get('email'),
                        'country': shop_data.get('country'),
                        'currency': shop_data.get('currency'),
                        'iana_timezone': shop_data.get('iana_timezone'),
                        'domain': shop_data.get('domain'),
                        'myshopify_domain': shop_data.get('myshopify_domain'),
                        'plan_name': shop_data.get('plan_name')
                    }
                    
                    logger.info(f"成功获取店铺信息: {shop_domain}")
                    return shop_info
                except json.JSONDecodeError:
                    logger.error(f"解析店铺信息JSON失败: {response.text}")
                    return None
            elif response:
                logger.error(f"获取店铺信息失败: {shop_domain}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取店铺信息请求失败: {shop_domain}")
                
            return None
                
        except Exception as e:
            logger.error(f"获取店铺信息异常: {shop_domain}, 错误: {str(e)}, 异常类型: {type(e).__name__}")
            return None
    
    def get_complete_shop_info(self, shop_domain: str, access_token: str) -> Optional[Dict]:
        """
        获取店铺完整信息，包括基本信息、元数据和客户统计
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: 有效的Shopify访问令牌
            
        Returns:
            Dict: 完整的店铺信息，如果获取失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, '/shop')
            headers = self._get_headers(access_token)
            
            logger.info(f"获取店铺完整信息: {shop_domain}")
            
            response = self._make_request('GET', url, headers)
            
            if response and response.status_code == 200:
                data = response.json()
                shop_data = data.get('shop', {})
                logger.info(f"成功获取店铺完整信息: {shop_domain}")
                return shop_data
            elif response:
                logger.error(f"获取店铺完整信息失败: {shop_domain}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取店铺完整信息请求失败: {shop_domain}")
                
            return None
            
        except Exception as e:
            logger.error(f"获取完整店铺信息异常: {shop_domain}, 错误: {str(e)}")
            return None
    
    def verify_access_token(self, shop_domain: str, access_token: str) -> bool:
        """
        验证访问令牌是否有效
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            
        Returns:
            bool: 令牌是否有效
        """
        # 基本验证
        if not all([shop_domain, access_token]):
            logger.error(f"Access token验证失败: 缺少必要参数，shop_domain={shop_domain}")
            return False
        
        # 验证access_token格式
        if not access_token.startswith(('shpat_', 'shpca_', 'shpss_')):
            logger.error(f"Access token验证失败: 无效的token格式，shop_domain={shop_domain}")
            return False
            
        try:
            url = self._build_shopify_url(shop_domain, '/shop')
            headers = self._get_headers(access_token)
            
            logger.info(f"开始验证access_token: {shop_domain}")
            response = self._make_request('GET', url, headers)
            
            # 根据不同状态码判断
            if response:
                if response.status_code == 200:
                    logger.info(f"Access token验证成功: {shop_domain}")
                    return True
                elif response.status_code == 401:
                    logger.error(f"Access token验证失败: token已过期或无效，shop_domain={shop_domain}, 状态码: 401")
                elif response.status_code == 403:
                    logger.error(f"Access token验证失败: 权限不足，shop_domain={shop_domain}, 状态码: 403")
                elif response.status_code == 429:
                    logger.warning(f"Access token验证警告: API速率限制，shop_domain={shop_domain}, 状态码: 429")
                    # 速率限制时也返回False，因为后续操作也会失败
                else:
                    logger.error(f"Access token验证失败: 未知状态码，shop_domain={shop_domain}, 状态码: {response.status_code}")
                
                # 尝试记录响应内容以帮助调试
                try:
                    error_data = response.json()
                    logger.error(f"API错误详情: {error_data}")
                except:
                    logger.error(f"响应内容: {response.text[:200]}...")  # 限制日志长度
                
                return False
            else:
                logger.error(f"Access token验证失败: 未收到API响应，shop_domain={shop_domain}")
                return False
                
        except Exception as e:
            logger.error(f"验证access token时出错: {shop_domain}, 错误类型: {type(e).__name__}, 错误信息: {str(e)}")
            return False
    
    def get_shop_metafields(self, shop_domain: str, access_token: str) -> Optional[List[Dict]]:
        """
        获取店铺元数据字段
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            
        Returns:
            List[Dict]: 元数据字段列表，如果获取失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, '/shop/metafields')
            headers = self._get_headers(access_token)
            
            response = self._make_request('GET', url, headers)
            
            if response and response.status_code == 200:
                data = response.json()
                metafields = data.get('metafields', [])
                logger.debug(f"成功获取店铺元数据，数量: {len(metafields)}")
                return metafields
            elif response:
                logger.error(f"获取店铺元数据失败: {shop_domain}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取店铺元数据请求失败: {shop_domain}")
                
            return None
                
        except Exception as e:
            logger.error(f"获取店铺元数据异常: {shop_domain}, 错误: {str(e)}")
            return None
    
    def get_shop_customer_count(self, shop_domain: str, access_token: str) -> Optional[int]:
        """
        获取店铺客户数量
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            
        Returns:
            int: 客户数量，如果获取失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, '/customers/count')
            headers = self._get_headers(access_token)
            
            response = self._make_request('GET', url, headers)
            
            if response and response.status_code == 200:
                data = response.json()
                return data.get('count')
            elif response:
                logger.error(f"获取店铺客户数量失败: {shop_domain}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取店铺客户数量请求失败: {shop_domain}")
                
            return None
                
        except Exception as e:
            logger.error(f"获取店铺客户数量异常: {shop_domain}, 错误: {str(e)}")
            return None
    
    def get_products(self, shop_domain: str, access_token: str, limit: int = 250, page: int = 1) -> Optional[List[Dict]]:
        """
        获取店铺产品列表
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            limit: 每页数量（最大250）
            page: 页码
            
        Returns:
            List[Dict]: 产品列表，如果获取失败返回None
        """
        try:
            # 确保limit不超过Shopify API的最大限制
            limit = min(limit, 250)
            
            url = self._build_shopify_url(shop_domain, '/products')
            headers = self._get_headers(access_token)
            params = {
                'limit': limit,
                'page': page,
                'fields': 'id,title,body_html,vendor,product_type,tags,published_scope,status,published_at,created_at,updated_at'
            }
            
            logger.info(f"获取产品列表: {shop_domain}, 页码: {page}, 每页数量: {limit}")
            response = self._make_request('GET', url, headers, params=params)
            
            if response and response.status_code == 200:
                data = response.json()
                products = data.get('products', [])
                logger.debug(f"成功获取产品列表，数量: {len(products)}")
                return products
            elif response:
                logger.error(f"获取产品列表失败: {shop_domain}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取产品列表请求失败: {shop_domain}")
                
            return None
                
        except Exception as e:
            logger.error(f"获取产品列表异常: {shop_domain}, 错误: {str(e)}")
            return None
    
    def get_all_products(self, shop_domain: str, access_token: str) -> List[Dict]:
        """
        获取店铺所有产品
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            
        Returns:
            List[Dict]: 所有产品列表
        """
        all_products = []
        page = 1
        limit = 250  # Shopify API最大限制
        max_pages = 100  # 设置最大页数限制，防止无限循环
        max_retries = 3
        retry_count = 0
        
        while page <= max_pages:
            products = self.get_products(shop_domain, access_token, limit, page)
            
            if products:
                all_products.extend(products)
                retry_count = 0  # 成功获取后重置重试计数
                
                # 如果获取的产品数量小于限制，说明已经获取完所有产品
                if len(products) < limit:
                    logger.info(f"已获取所有产品，最后一页数量: {len(products)}")
                    break
                
                page += 1
                logger.debug(f"继续获取产品列表: {shop_domain}, 页码: {page}")
                
                # 添加小延迟以避免触发速率限制
                if page % 5 == 0:  # 每5页添加一次延迟
                    logger.debug(f"批量获取中，添加延迟以避免速率限制")
                    time.sleep(1)
            else:
                # 处理失败情况
                retry_count += 1
                if retry_count > max_retries:
                    logger.error(f"获取产品列表失败次数过多，已达到最大重试次数: {max_retries}")
                    break
                
                logger.warning(f"获取产品列表失败，正在重试 ({retry_count}/{max_retries}): 页码 {page}")
                time.sleep(2 * retry_count)  # 指数退避
        
        logger.info(f"成功获取所有产品，共 {len(all_products)} 个: {shop_domain}")
        return all_products
    
    def create_product_metafield(self, shop_domain: str, access_token: str, product_id: int, namespace: str, key: str, value: str, value_type: str = 'string') -> Dict:
        """
        为产品创建或更新metafield
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            product_id: 产品ID
            namespace: metafield命名空间
            key: metafield键名
            value: metafield值
            value_type: metafield值类型 ('string', 'integer', 'json_string'等)
            
        Returns:
            Dict: 成功时返回创建的metafield信息，失败时返回包含错误详情的字典
        """
        # 初始化operation变量，避免UnboundLocalError
        operation = "操作"
        
        try:
            # 验证参数
            if not all([shop_domain, access_token, product_id, namespace, key, value]):
                logger.error(f"缺少必要参数: shop_domain={shop_domain}, product_id={product_id}, namespace={namespace}, key={key}")
                return {"error": "missing_required_params", "message": "缺少必要参数"}
            
            # 验证access_token格式
            if not access_token.startswith(('shpat_', 'shpca_', 'shpss_')):
                logger.error(f"无效的access_token格式: shop_domain={shop_domain}")
                return {"error": "invalid_token_format", "message": "无效的access_token格式"}
            
            headers = self._get_headers(access_token)
            payload = {
                'metafield': {
                    'namespace': namespace,
                    'key': key,
                    'value': value,
                    'value_type': value_type
                }
            }
            
            logger.info(f"创建/更新产品metafield: {shop_domain}, 产品ID: {product_id}, 键: {namespace}.{key}")
            
            # 先尝试获取已存在的metafield
            existing_metafield = self.get_product_metafield(shop_domain, access_token, product_id, namespace, key)
            
            if existing_metafield:
                # 更新现有metafield
                update_url = self._build_shopify_url(shop_domain, f'/products/{product_id}/metafields/{existing_metafield["id"]}')
                response = self._make_request('PUT', update_url, headers, json=payload)
                operation = "更新"
            else:
                # 创建新的metafield
                create_url = self._build_shopify_url(shop_domain, f'/products/{product_id}/metafields')
                response = self._make_request('POST', create_url, headers, json=payload)
                operation = "创建"
            
            # 详细日志记录请求结果
            logger.info(f"create_product_metafield API响应状态: {'成功' if response else '失败'}")
            
            if response and response.status_code in [200, 201]:
                try:
                    # 添加额外的JSON解析错误处理
                    data = response.json()
                    logger.info(f"成功{operation}产品metafield: {shop_domain}, 产品ID: {product_id}, 响应数据: {data}")
                    metafield_data = data.get('metafield') or data
                    return metafield_data  # 处理可能的不同响应格式
                except json.JSONDecodeError as json_error:
                    error_msg = f"{operation}产品metafieldJSON解析失败: {str(json_error)}"
                    logger.error(f"{error_msg}, 响应: {response.text}")
                    return {"error": "json_decode_error", "message": error_msg}
            elif response:
                error_msg = f"{operation}产品metafield失败，状态码: {response.status_code}"
                logger.error(f"{error_msg}, 响应: {response.text}")
                
                # 根据状态码返回特定的错误信息
                if response.status_code == 401:
                    return {"error": "unauthorized", "message": "API访问未授权，请检查access_token"}
                elif response.status_code == 403:
                    return {"error": "forbidden", "message": "API访问权限不足"}
                elif response.status_code == 404:
                    return {"error": "not_found", "message": "产品或资源未找到"}
                elif response.status_code == 429:
                    retry_after = response.headers.get('Retry-After', '未知')
                    return {"error": "rate_limited", "message": f"API速率限制，建议在{retry_after}秒后重试"}
                else:
                    return {"error": "api_error", "message": f"Shopify API错误: {response.status_code}, {response.text}"}
            else:
                logger.error(f"{operation}产品metafield请求失败: {shop_domain}, 产品ID: {product_id}")
                return {"error": "empty_response", "message": "API返回空响应，可能是网络问题或access_token无效"}
                
        except Exception as e:
            error_msg = f"{operation}产品metafield异常: {str(e)}"
            logger.error(f"{error_msg}, 异常类型: {type(e).__name__}")
            return {"error": "exception", "message": error_msg}
    
    def get_product_metafield(self, shop_domain: str, access_token: str, product_id: int, namespace: str, key: str) -> Optional[Dict]:
        """
        获取产品的指定metafield
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            product_id: 产品ID
            namespace: metafield命名空间
            key: metafield键名
            
        Returns:
            Dict: metafield信息，如果不存在或获取失败返回None
        """
        try:
            # 验证参数
            if not all([shop_domain, access_token, product_id, namespace, key]):
                logger.error(f"缺少必要参数: shop_domain={shop_domain}, product_id={product_id}, namespace={namespace}, key={key}")
                return None
            
            # 使用Shopify API的过滤功能直接查找指定的metafield
            url = self._build_shopify_url(shop_domain, f'/products/{product_id}/metafields')
            headers = self._get_headers(access_token)
            params = {
                'namespace': namespace,
                'key': key
            }
            
            response = self._make_request('GET', url, headers, params=params)
            
            if response and response.status_code == 200:
                data = response.json()
                metafields = data.get('metafields', [])
                
                if metafields:
                    # 应该只有一个匹配的metafield
                    metafield = metafields[0]
                    logger.info(f"找到产品metafield: {shop_domain}, 产品ID: {product_id}, 键: {namespace}.{key}")
                    return metafield
                
                logger.info(f"产品metafield不存在: {shop_domain}, 产品ID: {product_id}, 键: {namespace}.{key}")
                return None
            elif response:
                logger.error(f"获取产品metafield失败: {shop_domain}, 产品ID: {product_id}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取产品metafield请求失败: {shop_domain}, 产品ID: {product_id}")
                
            return None
            
        except Exception as e:
            logger.error(f"获取产品metafield异常: {shop_domain}, 产品ID: {product_id}, 错误: {str(e)}")
            return None
    
    def get_product_metafields(self, shop_domain: str, access_token: str, product_id: int) -> Optional[List[Dict]]:
        """
        获取产品的所有metafields
        
        Args:
            shop_domain: Shopify店铺域名
            access_token: Shopify访问令牌
            product_id: 产品ID
            
        Returns:
            List[Dict]: metafields列表，如果获取失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, f'/products/{product_id}/metafields')
            headers = self._get_headers(access_token)
            
            response = self._make_request('GET', url, headers)
            
            if response and response.status_code == 200:
                data = response.json()
                metafields = data.get('metafields', [])
                logger.debug(f"成功获取产品metafields，数量: {len(metafields)}")
                return metafields
            elif response:
                logger.error(f"获取产品metafields失败: {shop_domain}, 产品ID: {product_id}, 状态码: {response.status_code}, 响应: {response.text}")
            else:
                logger.error(f"获取产品metafields失败: {shop_domain}, 产品ID: {product_id}")
                
            return None
                
        except Exception as e:
            logger.error(f"获取产品metafields异常: {shop_domain}, 产品ID: {product_id}, 错误: {str(e)}")
            return None
    
    def admin_graphql_request(self, shop_domain: str, access_token: str, query: str, 
                            variables: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
        """
        发送Admin GraphQL API请求
        
        Args:
            shop_domain: 店铺域名
            access_token: 访问令牌
            query: GraphQL查询字符串
            variables: 查询变量（可选）
            
        Returns:
            Dict[str, Any]: API响应数据，如果失败返回None
        """
        try:
            # 构建请求URL
            url = self._build_shopify_url(shop_domain, "/graphql.json")
            
            # 准备请求头
            headers = self._get_headers(access_token)
            headers['Content-Type'] = 'application/json'
            
            # 准备请求数据
            payload = {
                'query': query
            }
            
            if variables:
                payload['variables'] = variables
            
            # 记录查询日志（不记录完整查询以避免日志过大）
            query_type = 'query' if query.strip().startswith('query') else 'mutation'
            logger.debug(f"发送Admin GraphQL {query_type} 请求到店铺: {shop_domain}")
            
            # 发送请求
            response = self._make_request("POST", url, headers, json=payload)
            
            # 处理响应
            if response and response.status_code == 200:
                try:
                    result = response.json()
                    
                    # 检查GraphQL错误
                    if 'errors' in result:
                        for error in result['errors']:
                            logger.error(f"GraphQL错误: {error.get('message')}")
                        return None
                    
                    return result
                except json.JSONDecodeError:
                    logger.error("GraphQL响应不是有效的JSON格式")
                    return None
            else:
                logger.error(f"GraphQL请求失败，状态码: {response.status_code if response else 'N/A'}")
                return None
                
        except Exception as e:
            logger.error(f"发送GraphQL请求时发生错误: {str(e)}")
            return None
    
    def storefront_graphql_request(self, shop_domain: str, access_token: str, query: str, 
                                 variables: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
        """
        发送Storefront GraphQL API请求
        
        Args:
            shop_domain: 店铺域名
            access_token: Storefront访问令牌
            query: GraphQL查询字符串
            variables: 查询变量（可选）
            
        Returns:
            Dict[str, Any]: API响应数据，如果失败返回None
        """
        try:
            # Storefront API使用不同的端点格式
            url = f"https://{shop_domain}/api/{self.api_version}/graphql.json"
            
            # 准备请求头（使用不同的认证头）
            headers = {
                'Content-Type': 'application/json',
                'X-Shopify-Storefront-Access-Token': access_token
            }
            
            # 准备请求数据
            payload = {
                'query': query
            }
            
            if variables:
                payload['variables'] = variables
            
            # 记录查询日志
            query_type = 'query' if query.strip().startswith('query') else 'mutation'
            logger.debug(f"发送Storefront GraphQL {query_type} 请求到店铺: {shop_domain}")
            
            # 发送请求
            response = self._make_request("POST", url, headers, json=payload)
            
            # 处理响应
            if response and response.status_code == 200:
                try:
                    result = response.json()
                    
                    # 检查GraphQL错误
                    if 'errors' in result:
                        for error in result['errors']:
                            logger.error(f"Storefront GraphQL错误: {error.get('message')}")
                        return None
                    
                    return result
                except json.JSONDecodeError:
                    logger.error("Storefront GraphQL响应不是有效的JSON格式")
                    return None
            else:
                logger.error(f"Storefront GraphQL请求失败，状态码: {response.status_code if response else 'N/A'}")
                return None
                
        except Exception as e:
            logger.error(f"发送Storefront GraphQL请求时发生错误: {str(e)}")
            return None
    
    def _handle_api_response(self, response: Optional[requests.Response]) -> Optional[Dict[str, Any]]:
        """
        统一处理API响应，包含错误检查和日志记录
        
        Args:
            response: 请求响应对象
            
        Returns:
            Dict[str, Any]: 解析后的响应数据，如果失败返回None
        """
        if not response:
            logger.error("API响应为空")
            return None
        
        try:
            # 检查状态码
            if response.status_code != 200:
                # 处理常见错误状态码
                if response.status_code == 401:
                    logger.error(f"API认证失败: {response.text}")
                elif response.status_code == 403:
                    logger.error(f"API权限不足: {response.text}")
                elif response.status_code == 429:
                    retry_after = response.headers.get('Retry-After', '未知')
                    logger.warning(f"API请求限流，建议在 {retry_after} 秒后重试")
                elif response.status_code >= 500:
                    logger.error(f"Shopify服务器错误，状态码: {response.status_code}")
                else:
                    logger.error(f"API请求失败，状态码: {response.status_code}, 响应: {response.text}")
                
                return None
            
            # 尝试解析JSON响应
            try:
                return response.json()
            except json.JSONDecodeError:
                logger.error("API响应不是有效的JSON格式")
                return None
                
        except Exception as e:
            logger.error(f"处理API响应时发生错误: {str(e)}")
            return None
    
    def create_webhook(self, shop_domain: str, access_token: str, webhook_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        创建Shopify webhook
        
        Args:
            shop_domain: 店铺域名
            access_token: 访问令牌
            webhook_data: webhook配置数据
            
        Returns:
            Dict[str, Any]: 创建的webhook信息，如果失败返回None
        """
        try:
            url = self._build_shopify_url(shop_domain, "/webhooks.json")
            headers = self._get_headers(access_token)
            
            payload = {'webhook': webhook_data}
            response = self._make_request("POST", url, headers, json=payload)
            
            if response and response.status_code == 201:
                result = response.json()
                logger.info(f"成功创建webhook: {result.get('webhook', {}).get('id')}")
                return result
            else:
                logger.error(f"创建webhook失败，状态码: {response.status_code if response else 'N/A'}")
                return None
                
        except Exception as e:
            logger.error(f"创建webhook时发生错误: {str(e)}")
            return None

# 创建服务实例
# 注意：在实际使用时，应该从环境变量或安全存储中获取API密钥
shopify_api_service = ShopifyApiService()